﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Linq;
using System.Reflection;
using System.Linq.Expressions;

namespace CoolCode.Data.Linq
{
    public class Repository<T> : IRepository<T>, IQueryable<T>, IEnumerable<T>, IDisposable  where T : class
    {
        private XDataContext db;

        internal Repository(XDataContext context)
        {
            this.db = context;
        }

        private Table<T> _table = null;

        protected virtual Table<T> table
        {
            get
            {
                if (_table == null)
                    _table = db.GetTable<T>();
                return _table;
            }
        }        

        #region IRepository<T> Members

        public virtual void Insert(T entity)
        {
            table.InsertOnSubmit(entity);
        }

        public virtual void Insert(IEnumerable<T> list)
        {
            table.InsertAllOnSubmit(list);
        }

        public virtual void Update(T entity)
        {
            table.Attach(entity, true);
        }

        public virtual void Update(T entity, T original)
        {
            table.Attach(entity, original);
        }

        public virtual void Update(IEnumerable<T> list)
        {
            table.AttachAll(list, true);
        }

        public virtual void Delete(T entity)
        {
            table.DeleteOnSubmit(entity);
        }

        public virtual void Delete(IQueryable<T> query)
        {
            table.DeleteAllOnSubmit(query);
        }

        public virtual void Delete(IEnumerable<T> list)
        {
            table.AttachAll(list);
            table.DeleteAllOnSubmit(list);
        }

        public virtual void Delete(Expression<Func<T, bool>> predicate)
        {
            var q = this.Query(predicate);
            table.DeleteAllOnSubmit(q);
        }

        public virtual IQueryable<T> Query()
        {
            return table;
        }

        public virtual IQueryable<T> Query(Expression<Func<T, bool>> predicate)
        {
            return table.Where(predicate);
        }

        IQueryable<T> IRepository<T>.Where(Expression<Func<T, bool>> predicate)
        {
            return table.Where(predicate);
        }

        public  List<T> List(IQueryable<T> query, bool withNoLock)
        {
            return db.ExecuteQuery<T>(query, withNoLock).ToList();
        }

        public virtual T Get(Expression<Func<T, bool>> predicate)
        {
            return this.table.FirstOrDefault(predicate);
        }

        public virtual ISingleResult<TResult> ExecuteStoredProcedure<TResult>(object instance, MethodInfo method, params object[] parameters)
        {
            IExecuteResult result = db.ExecuteStoredProcedure(instance, method, parameters);
            return ((ISingleResult<TResult>)result.ReturnValue);
        }

        public virtual IMultipleResults ExecuteStoredProcedure(object instance, MethodInfo method, params object[] parameters)
        {
            IExecuteResult result = db.ExecuteStoredProcedure(instance, method, parameters);
            return ((IMultipleResults)result.ReturnValue);
        }

        #endregion

        #region IEnumerable<T> Members

        public IEnumerator<T> GetEnumerator()
        {
            return this.table.GetEnumerator();
        }

        #endregion

        #region IEnumerable Members

        System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
        {
            return this.GetEnumerator();
        }

        #endregion

        #region IQueryable Members

        Type IQueryable.ElementType
        {
            get
            {
                return typeof(T);
            }
        }

        Expression IQueryable.Expression
        {
            get
            {
                return ((IQueryable) table).Expression; // return Expression.Constant(table);
            }
        }

        IQueryProvider IQueryable.Provider
        {
            get { return table; }
        }

        #endregion

        #region IDisposable Members

        public virtual  void Dispose()
        {
            if( db != null )
            {
                db.Dispose();
            }
        }

        #endregion
    }
     

}
